import {
  AbstractMesh,
  Color3,
  HighlightLayer,
  Mesh,
  PointerEventTypes,
  Scene,
  StandardMaterial,
  Vector3
} from '@babylonjs/core'
import { watch } from 'vue'
import { ref } from 'vue'

import createOptionJson from '@/utils/optional'

let id = 0

const checkAnchor = (mesh: AbstractMesh) => /^anchor_.*/.test(mesh.name)

const useAnchor = () => {
  const anchors = ref<AbstractMesh[]>([])
  const focused = ref<AbstractMesh>()
  let sceneInstance: Scene

  let highlightEffect: HighlightLayer

  watch(focused, (val, old) => {
    if (old) {
      highlightEffect.removeMesh(<Mesh>old)
    }
    if (val) {
      highlightEffect.addMesh(<Mesh>val, Color3.Red())
    }
  })

  const bindDel = (anchor: AbstractMesh) => {
    anchor.dispose()
    if (focused.value === anchor) {
      focused.value = undefined
    }
    anchors.value = anchors.value.filter((a) => a !== anchor)
  }

  const bindEvent = (scene: Scene) => {
    if (!sceneInstance) {
      sceneInstance = scene
    }
    if (!highlightEffect) {
      highlightEffect = new HighlightLayer('highlight', scene)
    }
    scene.onPointerObservable.add((pointerInfo) => {
      const { type, pickInfo, event } = pointerInfo
      if (!pickInfo) return

      if (type === PointerEventTypes.POINTERTAP) {
        console.log(pointerInfo)
        if (event.button === 0) {
          if (pickInfo.pickedMesh && checkAnchor(pickInfo.pickedMesh)) {
            return (focused.value = pickInfo.pickedMesh)
          } else {
            focused.value && (focused.value = undefined)
          }
        } else if (event.button === 2) {
          const { _x, _y, _z } = pickInfo.pickedPoint as Vector3

          if (focused.value) {
            focused.value.position = new Vector3(_x, _y, _z)
          } else {
            const anchor = Mesh.CreateSphere(`anchor_${++id}`, 32, 5, scene)
            const mate = new StandardMaterial('mate', scene)
            mate.emissiveColor = new Color3(1, 1, 1)
            anchor.material = mate
            anchor.position = new Vector3(_x, _y, _z)
            anchors.value.push(anchor)
            focused.value = anchor
          }
        }
      }
    })

    let alpha = 0
    scene.registerBeforeRender(() => {
      alpha += 0.06

      highlightEffect.blurHorizontalSize = 0.3 + Math.cos(alpha) * 0.6 + 0.6
      highlightEffect.blurVerticalSize = 0.3 + Math.sin(alpha / 3) * 0.6 + 0.6
    })
  }

  const bindSave = () => {
    if (!sceneInstance) return
    const option = createOptionJson(sceneInstance, anchors.value)

    console.log('option json', option)
  }

  return {
    anchors,
    focused,
    bindEvent,
    bindDel,
    bindSave
  }
}

export default useAnchor
